import { Component, Vue } from "vue-property-decorator";
import * as _ from 'lodash';

declare module 'vue/types/vue' {
// 3. 声明为 Vue 补充的东西
    interface Vue {
        error: { [key: string]: any };
        rules: { [key: string]: any };
        dataItem: string | undefined ;
        list: { [key: string]: any } ;
        pageNum: number;
        totalCount: number;
        dataList:any[string];

        handleCurrentChange(val: number): void;

        remoteValidatorInfo(rule: any, value: any, callback: any): any;

        remoteValidate(self: any, formName: string, postFnt: any): any;

        rowRemove (Remotefnt: (id: number) => Promise<any>, dataKey: number, dataList: any[], listKey: number, dataName: string): any;

        updateRowItem(self: any[string], formName: string, postFnt: any): any;

        totalDec(): void;

        totalInc(): void;

    }
}

@Component({})
export default class RemoteValidatorMixin extends Vue {

    public error: { [key: string]: any } = {};
    public rules: { [key: string]: any } = {};
    public dataItem: string | undefined;
    public list = {} as any;

    get pageNum() {
        return ( this.list && this.list.current_page) ? this.list.current_page : 0;
    }

    set pageNum(num) {
        this.list.current_page = num;
    }

    get per_page() {
        return this.list.per_page
    }

    get totalCount() {
        return this.list.total;
    }

    get dataList(): any[number] {
        if (this.list && this.list['data']) {
            return this.list['data'];
        } else {
            return [];
        }
    }

    public handleCurrentChange(val: number) {
        let self = this;
        self.$emit('update');
    }

    public totalInc() {
        if (this.list && this.list.total) {
            this.list.total++;
        }else {
            this.list.total = 1;
        }
    }

    public totalDec() {
        if (this.list && this.list.total) {
            this.list.total--;
            if (this.list.total < 0)
                this.list.total = 0
        } else {
            this.list.total = 0;
        }
    }

    public mounted() {

        if (this.fromData) {

            for (let itemKey in  this.fromData) {
                if (!this.rules[itemKey]) {
                    this.rules[itemKey] = [];
                }
                this.rules[itemKey].push({
                    validator: this.remoteValidatorInfo,
                    trigger: 'blur'
                });
            }
        }
    }

    get fromData(): { [key: string]: any } | undefined {
        if (this.dataItem) {
            return (this as any)[this.dataItem];
        }
        return undefined;
    }

    public remoteValidatorInfo(rule: any, value: any, callback: any) {
        if (this.error && this.error[rule.field]) {
            let message = this.error[rule.field];
            if (message) {
                this.error[rule.field] = undefined;
                return callback(new Error(message));
            }
        }
        return callback();
    }

    public remoteValidate(self: any, formName: string, postFnt: any) {
        return new Promise(function (resolve, reject) {
            self.$refs[formName].validate(async function (valid: boolean) {
                let remoteData;

                if (valid) {
                    remoteData = await postFnt(self[self.dataItem]);
                    if (!remoteData['success']) {
                        self.error = remoteData['error'];
                        self.$refs[formName].validate((valid: boolean) => {
                        });
                        reject(new Error('request error'));
                    } else {
                        resolve(remoteData['data']);
                    }
                } else {
                    reject(new Error('request error'));
                }
            });
        });
    }

    public rowRemove(Remotefnt: (id: number) => Promise<any>, dataKey: number, dataList: any[number], listKey: number, dataName: string) {
        let self: Vue = this;
        if (!dataName) {
            dataName = '数据';
        }
        this.$confirm('此操作将永久删除' + dataName + ', 是否继续?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(async function () {
            let data: any = await Remotefnt(dataKey);
            if (data.success) {
                dataList.splice(listKey, 1);
                self.totalDec();
                self.$message({
                    showClose: true,
                    message: '删除' + dataName + '成功'
                });
            } else {
                self.$message({
                    showClose: true,
                    message: '删除' + dataName + '失败'
                });
            }
        }).catch(() => {
            this.$message({
                type: 'info',
                message: '已取消删除'
            });
        });
    }

    /**
     * 用户更新数据列表，若通过key能找到，更新，不能找到，追加
     * @param listData
     * @param newData
     * @param keyName
     */
    public updateRowItem(listData: any, newData: any, keyName: string) {
        let findData: any = {};
        findData[keyName] = newData[keyName];
        let idx: string | undefined = _.findKey(listData, findData);
        if (idx) {
            _.assign(listData[idx], newData);
        } else {
            this.totalInc();
            listData.push(newData);
        }
    }
}
